package snow.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import snow.functional.Get;
import snow.functional.Set;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;

/**
 * 转换get/set方法引用为属性名工具类
 * @author : liqun
 * @createTime : 2022/5/30 10:44
 */
public class BeanUtils {
    private static final Logger log = LoggerFactory.getLogger(BeanUtils.class);

    /**
     * get方法获取字段名
     * @param fn
     * @param <T>
     * @return
     */
    public static <T> String convertToFieldName(Get<T> fn){
        SerializedLambda lambda = getSerializedLambda(fn);
        String methodName = lambda.getImplMethodName();
        String prefix = null;
        if(methodName.startsWith("get")){
            prefix = "get";
        }
        else if(methodName.startsWith("is")){
            prefix = "is";
        }
        if(prefix == null){
            log.warn("无效的getter方法: "+methodName);
        }
        // 截取get/is之后的字符串并转换首字母为小写（S为diboot项目的字符串工具类，可自行实现）
        return  toLowerFirstChar(methodName.replace(prefix, ""));
    }

    /**
     * set方法获取字段名
     * @param fn
     * @param <T>
     * @param <U>
     * @return
     */
    public static <T,U> String convertToFieldName(Set<T,U> fn){
        SerializedLambda lambda = getSerializedLambda(fn);
        String methodName = lambda.getImplMethodName();
        String prefix = null;
        if(methodName.startsWith("get")){
            prefix = "set";
        }
        if(prefix == null){
            log.warn("无效的setter方法: "+methodName);
        }
        // 截取set之后的字符串并转换首字母为小写（S为diboot项目的字符串工具类，可自行实现）
        return  toLowerFirstChar(methodName.replace(prefix, ""));
    }

    /**
     * 将字符串首字符转为小写
     * @param str
     * @return
     */
    public static String toLowerFirstChar(String str){
        if (Character.isLowerCase(str.charAt(0))){
            return str;
        }else {
            return Character.toLowerCase(str.charAt(0))+str.substring(1);
        }
    }

    /**
     * 获取serializedLambda实例方法
     * @param fn
     * @return
     */
    private static SerializedLambda getSerializedLambda(Serializable fn){
        //先检查缓存中是否已存在
        SerializedLambda lambda = null;
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            lambda = (SerializedLambda)method.invoke(fn);
        } catch (Exception e) {
            log.error("获取SerializedLambda异常, class="+fn.getClass().getSimpleName(), e);
        }
        return lambda;
    }
}
